﻿using System;
using System.IO;
using System.Text;
using System.Xml;
using HAPI;
using HuginApiAddonsCS.Extensions;

namespace HuginApiAddonsCS.Policy.PolicyGenerator
{
    public class PolicyGenerator
    {
        /// <summary>
        /// Generates a policy as a single xml file representing the whole tree, Calls the 
        /// generate policy tree method then converts the tree into an XML file
        /// </summary>
        /// <param name="inputNet">input net</param>
        /// <param name="actPrefix">action prefix</param>
        /// <param name="obsPrefix">observation prefix</param>
        /// <param name="outputDir">output directory for csvFiles</param>
        public void GenerateXmlPolicy(string inputNet, string actPrefix, string obsPrefix, string outputDir)
        {
            ParseListener pl = new DefaultClassParseListener();
            Domain inDomain = new Domain(inputNet, pl);
            PolicyNode rootNode = GeneratePolicyTree(inDomain, actPrefix, obsPrefix);

            //To XML
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.IndentChars = "\t";
            using (XmlWriter writer = XmlWriter.Create(outputDir, settings))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("PolicyTree");
                    
                rootNode.ToXmlWriter(writer);

                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }

        /// <summary>
        /// Generates a policy as a set of csv files with 1 file per node, 
        /// Calls the generate policy tree method then converts into a series of csv files
        /// </summary>
        /// <param name="inputNet">input net</param>
        /// <param name="actPrefix">action net</param>
        /// <param name="obsPrefix">observation prefix</param>
        /// <param name="outputFile">output XML file</param>
        public void GenerateCsvPolicy(string inputNet, string actPrefix, string obsPrefix, string outputFile)
        {
            ParseListener pl = new DefaultClassParseListener();
            Domain inDomain = new Domain(inputNet, pl);
            PolicyNode rootNode = GeneratePolicyTree(inDomain, actPrefix, obsPrefix);

            //To CSV files
            rootNode.WriteToCsvFile(outputFile);
        }

        /// <summary>
        /// Generates a policy as a set of csv files with 1 file per node, 
        /// Calls the generate policy tree method then converts into a series of csv files
        /// </summary>
        /// <param name="inputNet">input net</param>
        /// <param name="actPrefix">action net</param>
        /// <param name="obsPrefix">observation prefix</param>
        /// <param name="outputFile">output XML file</param>
        public void GenerateTikzPolicy(string inputNet, string actPrefix, string obsPrefix, string outputFile)
        {
            ParseListener pl = new DefaultClassParseListener();
            Domain inDomain = new Domain(inputNet, pl);
            PolicyNode rootNode = GeneratePolicyTree(inDomain, actPrefix, obsPrefix);

            //To Tikz file
            StringBuilder sb = new StringBuilder();

            sb.Append(@"\begin{tikzpicture}" + Environment.NewLine);
            sb.Append(@"\usetikzlibrary{positioning}" + Environment.NewLine);
            sb.Append(@"\usetikzlibrary{shadows}" + Environment.NewLine);
            sb.Append(@"\tikzstyle{action} = [ellipse, top color=white, bottom color=yellow!20, draw=yellow, node distance=1cm, drop shadow]" + Environment.NewLine);

            int treeLength = rootNode.GetTreeLength() - 1;
            float siblingDist = 1.4f;
            for (int i = treeLength; i > 0; i--)
            {
                sb.Append(@"\tikzstyle{level " + i + @"}=[level distance=1.5cm, sibling distance=" + siblingDist + "cm]" + Environment.NewLine);
                siblingDist = siblingDist*2;
            }

            sb.Append(rootNode.ToTikzString() + ";\n");

            sb.Append(@"\end{tikzpicture}");

            using (StreamWriter outFileWriter = new StreamWriter(outputFile))
            {
                outFileWriter.Write(sb.ToString());
            }
        }

        /// <summary>
        /// Generates a policy tree from an input net file
        /// </summary>
        /// <param name="inputNet">inoput net to generate tree from</param>
        /// <param name="actPrefix">action prefix</param>
        /// <param name="obsePrefix">observation prefix</param>
        /// <returns>root node of tree</returns>
        public PolicyNode GeneratePolicyTree(Domain inputNet, string actPrefix, string obsPrefix)
        {
            inputNet.Compile();

            int tFirst = inputNet.GetFirstTimeStep();
            PolicyNode rootNode = new PolicyNode((DiscreteNode)inputNet.GetNodeByName(actPrefix + tFirst), (DiscreteNode)inputNet.GetNodeByName(obsPrefix + (tFirst + 1)));

            return rootNode;
        }
    }
}
